package com.panda_coder.linedetector.watch;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.data.distributed.common.*;
import ohos.data.distributed.user.SingleKvStore;
import ohos.media.audio.AudioStreamInfo;
import ohos.rpc.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.utils.zson.ZSONArray;
import ohos.utils.zson.ZSONObject;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ConnectServiceAbility extends Ability {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
    private  Boolean isStarted=false;
    KvManagerConfig config;
    KvManager kvManager;
    private static final String STORE_ID = "distributed_db";
    private SingleKvStore singleKvStore;
    //采样率限定16000HZ
    private static final int VIDEO_SAMPLE_RATE = 16000;
    AudioCaptureUtils audioCaptureUtils=new AudioCaptureUtils(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO, VIDEO_SAMPLE_RATE);
    //录音线程
    private ThreadPoolExecutor poolExecutor;
    //线程池相关参数
    private static final int CAPACITY = 6;
    private static final int ALIVE_TIME = 3;
    private static final int POOL_SIZE = 3;
    //PCM流长度仅限640或1280
    private static final int BYTES_LENGTH = 1280;

    private static HashMap<Integer, IRemoteObject> remoteObjectHandlers = new HashMap<Integer, IRemoteObject>();

    JsConnectRemote remote = new JsConnectRemote();

    private SingleKvStore createDb() {
        SingleKvStore kvstore = null;
        try {
            Options options = new Options();
            options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION);
            kvstore = kvManager.getKvStore(options, STORE_ID);
        } catch (KvStoreException exception) {

        }
        return kvstore;
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        config = new KvManagerConfig(this.getContext());
        kvManager = KvManagerFactory.getInstance().createKvManager(config);
        singleKvStore = createDb();
        this.audioCaptureUtils.init("com.panda_coder.liedetector.watch");
        poolExecutor = new ThreadPoolExecutor(
                POOL_SIZE,
                POOL_SIZE,
                ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(CAPACITY),
                new ThreadPoolExecutor.DiscardOldestPolicy());
    }


    @Override
    public void onBackground() {
        super.onBackground();
        HiLog.info(LABEL_LOG, "ConnectServiceAbility::onBackground");
    }

    @Override
    public void onStop() {
        super.onStop();
        HiLog.info(LABEL_LOG, "ConnectServiceAbility::onStop");
    }

    @Override
    public void onCommand(Intent intent, boolean restart, int startId) {
    }

    @Override
    public IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        return remote.asObject();
    }

    class JsConnectRemote extends RemoteObject implements IRemoteBroker {
        JsConnectRemote() {
            super("jsConnectRemote");
        }

        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
            Map<String, Object> zsonResult = new HashMap<String, Object>();
            String zsonStr = data.readString();
            ZSONObject zson = ZSONObject.stringToZSON(zsonStr);
            switch (code) {
                case 100: {
                    String hearts = zson.getString("hearts");
                    singleKvStore.putString("before_heart", hearts);
                    break;
                }
                case 101: {
                    String hearts = zson.getString("hearts");
                    singleKvStore.putString("after_heart", hearts);
                    break;
                }
                case 200:{
                    poolExecutor.submit(new AudioCaptureRunnable());
                    isStarted=true;
                    break;
                }
                case 201:{
                    isStarted=false;
                    audioCaptureUtils.stop();
                    poolExecutor.shutdown();
                    break;
                }
                case 300:{
                    remoteObjectHandlers.put(300, data.readRemoteObject());
                    getAsrText();
                    break;
                }
                case 301:{
                    break;
                }
                default: {
                    reply.writeString("service not defined");
                    return false;
                }
            }
            reply.writeString(ZSONObject.toZSONString(zsonResult));
            return true;
        }

        @Override
        public IRemoteObject asObject() {
            return this;
        }
    }

    private class AudioCaptureRunnable implements Runnable{
        @Override
        public void run() {
            byte[] buffers=new byte[BYTES_LENGTH];
            audioCaptureUtils.start();
            while (isStarted){
                int ret=audioCaptureUtils.read(buffers, 0, BYTES_LENGTH);
                if(ret>0){
                    singleKvStore.putByteArray("PCM",buffers);
                }
            }
        }
    }

    @Override
    public void onDisconnect(Intent intent) {
    }


    public void getAsrText() {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1 * 500);
                    Map<String, Object> zsonResult = new HashMap<String, Object>();
                    String text="";
                    try{
                        text=singleKvStore.getString("audio_text");
                    }catch (Exception ex){

                    }
                    singleKvStore.delete("audio_text");
                    zsonResult.put("audio_text",text);
                    ReportEvent(300, zsonResult);
                } catch (RemoteException | InterruptedException e) {
                    break;
                }
            }
        }).start();
    }

    private void ReportEvent(int remoteHandler, Object backData) throws RemoteException {
        MessageParcel data = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        MessageOption option = new MessageOption();
        data.writeString(ZSONObject.toZSONString(backData));
        IRemoteObject remoteObject = remoteObjectHandlers.get(remoteHandler);
        remoteObject.sendRequest(100, data, reply, option);
        reply.reclaim();
        data.reclaim();
    }

}